using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using WpfWordsLearner.Helper;
using System.ComponentModel;
using System.Threading.Tasks;

namespace WpfWordsLearner.ViewModels
{
	public class LearnViewModel : BaseViewModel, IDisposable
	{
		public List<int> WordsCount
		{
			get;
			private set;
		}

		public List<int> Intervals
		{
			get;
			private set;
		}

		public int SelectedCount
		{
			get;
			set;
		}

		private int m_milsec;
		public int Interval
		{
			get { return m_milsec; }
			set { m_milsec = value; OnPropertyChanged(() => Interval); }
		}

		private Queue<Model.LearnItem> m_words;
		public Queue<Model.LearnItem> Words
		{
			get { return m_words; }
			set { m_words = value; }
		}

		public List<Model.LearnItem> ForTest
		{
			get;
			set;
		}

		private Model.LearnItem m_word;
		public Model.LearnItem WordToLearn
		{
			get { return m_word; }
			set
			{
				m_word = value;
				OnPropertyChanged(() => WordToLearn);
			}
		}

		private bool m_isEnd;
		public bool Completed
		{
			get { return m_isEnd; }
			set
			{
				m_isEnd = value;
				OnPropertyChanged(() => Completed);
			}
		}

		private bool m_btnEnaled;
		public bool EnableButton
		{
			get { return m_btnEnaled; }
			set { m_btnEnaled = value; OnPropertyChanged(() => EnableButton); }
		}

		private bool m_onlyCompl;
		public bool OnlyComplicated
		{
			get { return m_onlyCompl; }
			set
			{
				m_onlyCompl = value;
				OnPropertyChanged(() => OnlyComplicated);
			}
		}

		private bool m_useVoice;
		public bool UseVoice
		{
			get { return m_useVoice; }
			set
			{
				m_useVoice = value; OnPropertyChanged(() => UseVoice);
			}
		}

		private int remein;
		public int Remain
		{
			get { return remein; }
			set
			{
				remein = value;
				OnPropertyChanged(() => Remain);
			}
		}

		Task learnTask = null;
		System.Threading.CancellationTokenSource m_cts = null;
		System.Windows.Threading.Dispatcher m_windDisp = null;
		DAO.WordsDaoPlain m_dao = null;

		public LearnViewModel()
		{
			//voiceManager = new VoiceManager();
			Completed = false;
			EnableButton = true;
			Words = new Queue<Model.LearnItem>();
			WordsCount = new List<int>();
			m_dao = new DAO.WordsDaoPlain(App.pathToDB);

			for (int i = 5; i <= 50; i++)
			{
				WordsCount.Add(i);
			}

			Intervals = new List<int>();
			for (int i = 3; i <= 10; i++)
			{
				Intervals.Add((int)TimeSpan.FromSeconds(i).TotalMilliseconds);
			}
		}

		public void SetDispatcher(System.Windows.Threading.Dispatcher disp)
		{
			m_windDisp = disp;
		}

		public ICommand BeginLearnCommand { get { return new BaseCommand(LearnExecuted, new Func<bool>(CanExecute)); } }
		private void LearnExecuted()
		{
			ServiceReferenceTranslater.TranslateServiceClient client = new ServiceReferenceTranslater.TranslateServiceClient();

			m_cts = new System.Threading.CancellationTokenSource();
			learnTask = new Task(new Action(() =>
			{
				Completed = false;
				EnableButton = false;
				ForTest = new List<Model.LearnItem>();
				int intr = Interval; Remain = 0;

				List<Model.LearnItem> generation = null;
				LerningModelGenerator gen = new LerningModelGenerator(SelectedCount);

				if (!OnlyComplicated)
					generation = gen.GenerateLearningCourse();
				else
					generation = gen.GenerateLearningCourseComplicated();

				foreach (Model.LearnItem item in generation)
				{
					ForTest.Add(item);
					Words.Enqueue(item);
					Remain++;
				}

				System.Threading.Thread.Sleep(300);

				while (Words != null && Words.Count > 0)
				{
					if (m_cts.IsCancellationRequested)
						break;

					m_windDisp.Invoke(new Action(() => { WordToLearn = Words.Dequeue(); Remain--; }),
						System.Windows.Threading.DispatcherPriority.Background);

					if (UseVoice)
					{
						System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(Voice), client);
					}

					if (Words.Count > 0)
						System.Threading.Thread.Sleep(Interval);
					else
						System.Threading.Thread.Sleep(500);
				}
			}), m_cts.Token, TaskCreationOptions.LongRunning);

			learnTask.ContinueWith(prevTask =>
			{
				m_windDisp.Invoke(new Action(() =>
				{
					Completed = true; EnableButton = true; prevTask.Dispose();
					if (client != null)
					{
						if (client.State == System.ServiceModel.CommunicationState.Faulted ||
							client.State == System.ServiceModel.CommunicationState.Closed)
							return;
						if (client.State == System.ServiceModel.CommunicationState.Opened)
							try
							{
								client.Close();
							}
							catch (Exception ex)
							{
								App.Log.Error("Close method throws exception", ex); client.Abort();
							}
					}
				}),
					System.Windows.Threading.DispatcherPriority.Background);
			}, TaskContinuationOptions.OnlyOnRanToCompletion);

			learnTask.ContinueWith(prevTask =>
			{
				App.Log.Error(WpfWordsLearner.Properties.Resources.msgWordsLearnError, prevTask.Exception.Flatten());
				m_windDisp.Invoke(new Action(() =>
				{
					Completed = true; EnableButton = true; prevTask.Dispose();
					if (client != null)
					{
						if (client.State == System.ServiceModel.CommunicationState.Faulted ||
							client.State == System.ServiceModel.CommunicationState.Closed)
							return;
						if (client.State == System.ServiceModel.CommunicationState.Opened)
							try
							{
								client.Close();
							}
							catch (Exception ex)
							{
								App.Log.Error("Close method throws exception", ex); client.Abort();
							}
					}
				}),
					System.Windows.Threading.DispatcherPriority.Background);
			}, TaskContinuationOptions.NotOnRanToCompletion);

			learnTask.Start();
		}

		private bool CanExecute()
		{
			return true;
		}

		private void Voice(object client)
		{
			if (client != null && client is ServiceReferenceTranslater.TranslateServiceClient)
			{
				VoiceManager2 voiceManager = null;
				try
				{
					voiceManager = new VoiceManager2();
					if (!m_dao.IsWordVoiced(WordToLearn.Word))
					{
						var voiceReq = new ServiceReferenceTranslater.VoiceRequest();
						voiceReq.ToLanguage = "en";
						voiceReq.OriginalText = WordToLearn.Word;

						try
						{
							var response = (client as ServiceReferenceTranslater.TranslateServiceClient).GetVoice(voiceReq);
							if (response != null && response.Data != null)
							{
								m_dao.AddVoicedWord(WordToLearn.Word, response.Data);

								System.IO.Stream stream = new System.IO.MemoryStream(response.Data);
								voiceManager.Play(stream);
								stream.Dispose();
							}
						}
						catch (System.ServiceModel.FaultException<ServiceReferenceTranslater.VoiceFault>) { }
					}
					else
					{
						byte[] data = m_dao.GetVoiceForWord(WordToLearn.Word);

						System.IO.Stream stream = new System.IO.MemoryStream(data);
						voiceManager.Play(stream);
						stream.Dispose();
					}
				}
				catch (System.ServiceModel.FaultException<ServiceReferenceTranslater.VoiceFault> ex)
				{
					App.Log.Error(string.Format("{0}{1}{2}{3}", "Error was occurred while voicing", Environment.NewLine, ex.Message, ex));
				}
				catch (System.ServiceModel.FaultException ex)
				{
					App.Log.Error("Error was occurred while voicing", ex);
				}
				catch (Exception ex)
				{
					App.Log.Error("Error was occurred while voicing", ex);
				}
				finally { voiceManager.Dispose(); }
			}
		}

		public ICommand ClosingWinCommand { get { return new Catel.MVVM.Command<System.ComponentModel.CancelEventArgs>(CloseWind); } }

		private void CloseWind(System.ComponentModel.CancelEventArgs e)
		{
			System.Windows.Window wind = App.Current.Windows.Cast<System.Windows.Window>().FirstOrDefault(x => x.IsActive);
			if (wind != null && wind.DataContext != null && wind.DataContext is ViewModels.LearnViewModel)
			{
				(wind.DataContext as ViewModels.LearnViewModel).Dispose();
				if ((wind.DataContext as ViewModels.LearnViewModel).CloseWindowExecuted)
				{
					Views.TestAfterLearnWindow testWind = new Views.TestAfterLearnWindow();
					testWind.Owner = wind.Owner;
					testWind.WindowStyle = System.Windows.WindowStyle.ToolWindow;
					testWind.ShowInTaskbar = false;
					testWind.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;

					var vm = new WpfWordsLearner.ViewModels.TestViewModel();
					vm.SetTestSettings((wind.DataContext as ViewModels.LearnViewModel).ForTest);

					testWind.DataContext = vm;
					testWind.Show();
				}
			}
		}

		public void Dispose()
		{
			if (learnTask != null && !learnTask.IsCompleted)
				m_cts.Cancel();

			m_windDisp = null;
			m_words = null;
			m_dao.Dispose();
		}
	}
}
